#include "blockNode.h"

BlockNode::~BlockNode()
{
	ClearChild();
}

char BlockNode::GetChar() const
{
	if(_type != TYPE_INT8)
	{
		char log[101] = { 0 };
		snprintf(log, 100, "BlockNode::GetChar, _type: %d", (int)_type);
		throw BlockNodeException(log);
	}

	if(m_data.empty())
		throw BlockNodeException("BlockNode::GetChar, data is empty");

	return (char)ParseInt(m_data.c_str());
}

int16 BlockNode::GetShort() const
{
	if(_type != TYPE_INT16)
	{
		char log[101] = { 0 };
		snprintf(log, 100, "BlockNode::GetShort, _type: %d", (int)_type);
		throw BlockNodeException(log);
	}

	if(m_data.empty())
		throw BlockNodeException("BlockNode::GetShort, data is empty");

	return (int16)ParseInt(m_data.c_str());
}

int BlockNode::GetInt() const
{
	if(_type != TYPE_INT32)
	{
		char log[101] = { 0 };
		snprintf(log, 100, "BlockNode::GetInt, _type: %d", (int)_type);
		throw BlockNodeException(log);
	}

	if(m_data.empty())
		throw BlockNodeException("BlockNode::GetInt, data is empty");

	return ParseInt(m_data.c_str());
}

int64 BlockNode::GetInt64() const
{
	if(_type != TYPE_INT64)
	{
		char log[101] = { 0 };
		snprintf(log, 100, "BlockNode::GetInt64, _type: %d", (int)_type);
		throw BlockNodeException(log);
	}

	if(m_data.empty())
		throw BlockNodeException("BlockNode::GetInt64, data is empty");

	int64 data;
	sscanf(m_data.c_str(), "%lld", &data);
	
	return data;
}

double BlockNode::GetDouble() const
{
	if(_type != TYPE_DOUBLE)
	{
		char log[101] = { 0 };
		snprintf(log, 100, "BlockNode::GetDouble, _type: %d", (int)_type);
		throw BlockNodeException(log);
	}
	
	if(m_data.empty())
		throw BlockNodeException("BlockNode::GetDouble, data is empty");

	return atof(m_data.c_str());
}

string BlockNode::GetString() const
{
	if(_type != TYPE_STRING)
	{
		char log[101] = { 0 };
		snprintf(log, 100, "BlockNode::GetString, _type: %d", (int)_type);
		throw BlockNodeException(log);
	}

	if(m_data.empty())
		throw BlockNodeException("BlockNode::GetString, data is empty");

	return m_data;
}

void BlockNode::SetChar(char v)
{
	_type = TYPE_INT8;

	char data[20];
	snprintf(data, sizeof(data)-1, "%d", v);
	this->m_data = data;
}

void BlockNode::SetShort(int16 v)
{
	_type = TYPE_INT16;
	
	char data[20];
	snprintf(data, sizeof(data)-1, "%d", v);
	this->m_data = data;
}

void BlockNode::SetInt(int v)
{
	_type = TYPE_INT32;
	
	char data[20];
	snprintf(data, sizeof(data)-1, "%d", v);
	this->m_data = data;
}

void BlockNode::SetInt64(int64 v)
{	
	_type = TYPE_INT64;

	char data[20];
	snprintf(data, sizeof(data)-1, "%lld", v);
	this->m_data = data;
}

void BlockNode::SetDouble(double v)
{
	_type = TYPE_DOUBLE;

	char data[20];
	snprintf(data, sizeof(data)-1, "%lf",  v);
	this->m_data = data;
}

void BlockNode::SetString(const string& v)
{
	_type = TYPE_STRING;

	this->m_data = v;
}

bool BlockNode::HasChild() const
{
	return !_children.empty();
}

inline bool BlockNode::IsEmpty() const
{
	return (!HasChild() && m_data.empty());
}

BlockNode* BlockNode::GetParent() const
{
	return _parent;
}

BlockNode* BlockNode::GetFirstChild(NodeIterator& iter) const
{
	iter = _children.begin();
	if (iter != _children.end())
		return *iter;

	return NULL;
}

BlockNode* BlockNode::GetNextChild(NodeIterator& iter) const
{
	if (iter != _children.end())
	{
		++iter;
		if(iter != _children.end())
			return *iter;
	}

	return NULL;
}

BlockNode* BlockNode::GetChild(NodeIterator iter) const
{
	if(iter != _children.end())
		return *iter;

	return NULL;
}

BlockNode* BlockNode::GetBackChild() const
{
	return _children.empty() ? NULL : _children.back();
}

BlockNode* BlockNode::FindFirstChild(uint16 key, NodeIterator& iter) const
{
	iter = _children.begin();
	while(iter != _children.end())
	{
		if((*iter) != NULL && (*iter)->GetKey() == key)
			return *iter;

		++iter;
	}

	return NULL;
}

BlockNode* BlockNode::FindNextChild(uint16 key, NodeIterator& iter) const
{
	if(iter != _children.end())
	{
		while(++iter != _children.end())
		{
			if((*iter) != NULL && (*iter)->GetKey() == key)
				return (*iter);
		}
	}

	return NULL;
}

void BlockNode::ClearChild()
{
	vector<BlockNode*>::iterator iter = _children.begin();
	for(; iter != _children.end(); ++iter)
	{
		ASSERT((*iter) != NULL);

		SAFE_DELETE(*iter);
	}

	_children.clear();
}

BlockNode* BlockNode::AddChild(uint16 key)
{
	ASSERT(this->_type == TYPE_BLOCK);

	BlockNode* child = SAFE_NEW BlockNode(key, this);
	_children.push_back( child );

	return child;
}

int16 BlockNode::Tree2Packet(ByteBuffer& pack)
{
	if(_type ==  TYPE_BLOCK && IsEmpty())
		return 0;

	vector<BlockNode*>::iterator it = _children.begin();
	
	int nodeLen = 0;

	while(it != _children.end())
	{
		if((*it)->GetType() == TYPE_BLOCK)
		{
			ByteBuffer tmppck;
			int tmplen = (*it)->Tree2Packet(tmppck);
			if(tmplen < 0)
				return -1;
			pack<<(uint16)(5 + tmplen)<<(*it)->GetKey()<<(uint8)TYPE_BLOCK;
			if(tmplen > 0) pack.Append(tmppck.Data(), tmplen);
			nodeLen += 5 + tmplen;
		}
		else
		{
			int strlenth = 0;
			switch((*it)->GetType())
			{
			case TYPE_STRING:
				strlenth = (*it)->GetString().size();
				pack<<(uint16)(5 + strlenth)<<(*it)->GetKey()<<(uint8)TYPE_STRING;
				if(strlenth > 0) pack.Append((const uint8*)(*it)->GetString().c_str(), strlenth);
				nodeLen += (5 + strlenth);
				break;

			case TYPE_INT8:
				pack<<(uint16)(6)<<(*it)->GetKey()<<(uint8)TYPE_INT8;
				pack<<(*it)->GetChar();
				nodeLen += 5 + 1;
				break;

			case TYPE_INT16:
				pack<<(uint16)(7)<<(*it)->GetKey()<<(uint8)TYPE_INT16;
				pack<<(*it)->GetShort();
				nodeLen += 5 + 2;
				break;

			case TYPE_INT32:
				pack<<(uint16)(9)<<(*it)->GetKey()<<(uint8)TYPE_INT32;
				pack<<(*it)->GetInt();
				nodeLen += 5 + 4;
				break;

			case TYPE_DOUBLE:
				pack<<(uint16)(13)<<(*it)->GetKey()<<(uint8)TYPE_DOUBLE;
				pack<<(*it)->GetDouble();
				nodeLen += 5 + 8;
				break;

			case TYPE_INT64:
				pack<<(uint16)(13)<<(*it)->GetKey()<<(uint8)TYPE_INT64;
				pack<<(*it)->GetInt64();
				nodeLen += 5 + 8;
				break;

			default:
				return -1;
			}
		}	
		++it;		
	}

	return nodeLen;
}

bool BlockNode::CreatTreeFromPacket(ByteBuffer& pack, uint16& parsed_len, bool is_root/*=true*/)
{
	uint16 data_odd;
	uint8 *buf = NULL;

	try
	{
		if (!is_root)
		{
			pack >> parsed_len >> _key >> _type;
			switch(_type)
			{
			case TYPE_INT8:
				int8 v;
				pack >> v;
				SetChar(v);
				return true;
			case TYPE_INT16:
				int16 v1;
				pack >> v1;
				SetShort(v1);
				return true;
			case TYPE_INT32:
				int32 v2;
				pack >> v2;
				SetInt(v2);				
				return true;
			case TYPE_DOUBLE:
				double v3;
				pack >> v3;
				SetDouble(v3);
				return true;
			case TYPE_INT64:
				int64 v4;
				pack>>v4;
				SetInt64(v4);
				return true;
			case TYPE_STRING:
				buf = SAFE_NEW uint8[parsed_len - 4];
				if(!buf)
					return false;
				memset(buf, 0, parsed_len-4);
				if (parsed_len-5 > 0 )
					pack.Reduce(buf, parsed_len-5);
				SetString((const char*)buf);
				SAFE_DELETE(buf);
				buf = NULL;
				return true;
			case TYPE_BLOCK:
				data_odd = parsed_len - 5;
				break;
			default:
				return false;
			}
		}
		else
		{
			data_odd = pack.Size();
			parsed_len = data_odd;
		}

		while(data_odd > 0)
		{
			BlockNode* node = AddChild();
			uint16 data_parsed = 0;
			if(!node->CreatTreeFromPacket(pack, data_parsed, false))
			{
				return false;
			}
			data_odd -= data_parsed;
		}
	}
	catch(...)
	{
		return false;
	}

	return 	true;
}

BlockTree::BlockTree()
: BlockNode(KEY_ROOT, NULL)
{	
}

bool BlockTree::LoadFromNetPacket(ByteBuffer& pack)
{
	uint16 parsed_len;
	return CreatTreeFromPacket(pack, parsed_len, true);
}

bool BlockTree::FillUpNetPacket(ByteBuffer& pack)
{
	if(Tree2Packet(pack) < 0)
		return false;

	return true;
}
